#include "OgreStableHeaders.h"
#include "OgreArchiveManager.h"

#include "OgreArchiveFactory.h"
#include "OgreArchive.h"
#include "OgreException.h"
#include "OgreLogManager.h"

namespace Ogre
{
typdef void (*createFunc)(Archive**, const String&);

template<> ArchiveManager* Singleton<ArchiveManager>::ms_Singleton = 0;
ArchiveManager* ArchiveManager::getSingletonPtr(void)
{
	return ms_Singleton;
}

ArchiveManager& ArchiveManager::getSingleton(void)
{
	assert(ms_Singleton); return (*ms_Singleton);
}

ArchiveManager::ArchiveManager()
{
}

Archive* ArchiveManager::load(const String& filename, const String& archiveType)
{
	ArchiveMap::iterator i = mArchives.find(filename);
	Archive* pArch = 0;
	
	if (i == mArchives.end())
	{
		ArchiveFactoryMap::iterator it = mArchiveFactories.find(archiveType);
		if (it == mArchiveFactories.end())
			OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Cannot find an archive factory "
				"to deal with archive of type " + archiveType, "ArchiveManager::load");
				
		pArch = it->second->createInstance(filename);
		pArch->load();
		mArchives[filename] = pArch;
	}
	else
	{
		pArch = i->second;
	}
	return pArch;
}

void ArchiveManager::unload(Archive* arch)
{
	unload(arch->getName());
}

void ArchiveManager::unload(const String& filename)
{
	ArchiveMap::iterator i = mArchives.find(filename);
	
	if (i != mArchives.end())
	{
		i->second->unload();
		ArchiveFactoryMap::iterator fit = mArchFactories.find(i->second->getType());
		if (fit == mArchFactories.end())
		{
			OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Cannot find an archive factory "
				"to deal with archive of type " + i->second->getType(), "ArchiveManager::~ArchiveManager");
		}
		fit->second->destroyInstance(i->second);
		mArchives.erase(i);
	}
}

ArchiveManager::ArchiveMapIterator ArchiveManager::getArchiveIterator(void)
{
	return ArchiveMapIterator(mArchives.begin(), mArchives.end());
}

ArchiveManager::~ArchiveManager()
{
	for (ArchiveMap::iterator it = mArchives.begin(); it != mArchives.end(); ++it)
	{
		Archive* arch = it->second;
		arch->unload();
		ArchiveFactoryMap::iterator fit = mArchFactories.find(arch->getType());
		if (fit == mArchFactories.end())
		{
			OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Cannot find an archive factory "
				"to deal with archive of type " + arch->getType(), "ArchiveManager::~ArchiveManager");
		}
		fit->second->destroyInstance(arch);
	}
	
	mArchives.clear();
}

void ArchiveManager::addArchiveFactory(ArchiveFactory* factory)
{
	mArchFactories.insert(ArchiveFactoryMap::value_type(factory->getType(), factory));
	LogManager::getSingleton().logMessage("ArchiveFactory for archive type " + factory->getType() + " registered.");
}
}
